package top.chmin.project.cloud.common.dao;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import top.chmin.project.cloud.common.entity.Condition;
import top.chmin.project.cloud.common.entity.Model;
import top.chmin.project.cloud.common.entity.Page;
import top.chmin.project.cloud.common.tool.LocalTool;

import java.util.List;
import java.util.stream.Stream;

/**
 * chmin
 * 2023/12/15 9:05
 * cloud-builder
 */
@Slf4j
public abstract class BaseDao<E extends Model> {
    @Resource
    protected JdbcTemplate template;

    public abstract int save(E e);

    public abstract int save(List<E> list);

    public abstract int updateById(E e);

    public abstract int deleteById(Long id);

    public abstract int deleteById(List<Long> list);

    public abstract E getById(Long id);

    public abstract List<E> getListById(List<Long> list);

    public int updateByCondition(Condition condition) {
        return template.update(condition.getSql(), condition.getValueList().toArray());
    }

    public int deleteByCondition(Condition condition) {
        return template.update(condition.getSql(), condition.getValueList().toArray());
    }

    public abstract E getFirst(Condition condition);

    public <T> T getFirst(Condition condition, Class<T> clazz) {
        return template.queryForStream(condition.getSql()+ " LIMIT 1", new BeanPropertyRowMapper<>(clazz), condition.getValueList().toArray()).findFirst().orElse(null);
    }

    public abstract Stream<E> getStreamByCondition(Condition condition);

    public <T> Stream<T> getStreamByCondition(Condition condition, Class<T> clazz) {
        return template.queryForStream(condition.getSql(), new BeanPropertyRowMapper<>(clazz), condition.getValueList().toArray());
    }

    public abstract Page<E> getPageByCondition(Condition condition);

    public <T> Page<T> getPageByCondition(Condition condition, Class<T> clazz) {
        Condition countCondition = new Condition()
                .setSql("select count(id) " + condition.getSql().substring(condition.getSql().indexOf("FROM")))
                .setValueList(condition.getValueList());
        var count = countByCondition(countCondition);
        if (count == 0) {
            return new Page<>();
        }
        Condition listCondition = new Condition()
                .setSql(condition.getSql() + " LIMIT %s,%s".formatted(
                        (Math.min(LocalTool.getPage().getPage() - 1, (count + LocalTool.getPage().getPageSize() - 1) / LocalTool.getPage().getPageSize())) * LocalTool.getPage().getPageSize(),
                        LocalTool.getPage().getPageSize()
                ))
                .setValueList(condition.getValueList());
        return new Page<T>(LocalTool.getPage()).setTotal(count).setList(getStreamByCondition(listCondition, clazz).toList());
    }

    public int countByCondition(Condition condition) {
        var result = template.queryForObject(condition.getSql(), Integer.class, condition.getValueList().toArray());
        return result == null ? 0 : result;
    }
}
